package com.brillilab.service.module.aliyun;

import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.push.model.v20160801.*;
import com.aliyuncs.utils.ParameterHelper;
import com.brillilab.domain.vo.message.AliPushVo;
import com.brillilab.service.module.message.enums.AppPushTypeEnum;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Component
@ConfigurationProperties(prefix="aliyun.push")
@Data
public class AliYunPush {

    private String regionId;
    private String accessKeyId;
    private String accessKeySecret;
    private long androidKey;
    private long iosKey;
    private String env;

    private DefaultAcsClient getClient() {
        IClientProfile profile=DefaultProfile.getProfile(regionId,accessKeyId,accessKeySecret);
        return new DefaultAcsClient(profile);
    }

    /**
     * 异步推送
     *
     * @param aliPushVo
     * @throws Exception 参见文档 https://help.aliyun.com/document_detail/48089.html //
     */
    @Async
    public void asyncPush(AliPushVo aliPushVo) throws Exception {
        syncPush(aliPushVo);
    }

    /**
     * 同步推送(建议使用asyncPush异步方法)
     *
     * @param aliPushVo
     * @throws Exception 参见文档 https://help.aliyun.com/document_detail/48089.html //
     */
    public PushResponse syncPush(AliPushVo aliPushVo) throws Exception {
        PushRequest pushRequest=new PushRequest();
        // 安全性比较高的内容建议使用HTTPS
        pushRequest.setProtocol(ProtocolType.HTTPS);
        // 内容较大的请求，使用POST请求
        pushRequest.setMethod(MethodType.POST);

        // 推送目标
        pushRequest.setPushType(aliPushVo.getPushType());
        pushRequest.setDeviceType(aliPushVo.getDeviceType());
        pushRequest.setTarget(aliPushVo.getTarget());
        pushRequest.setTargetValue(aliPushVo.getTargetValue());

        String paramJson=JSONObject.toJSONString(aliPushVo.getParamMap());
        if("iOS".equals(aliPushVo.getDeviceType())){
            pushRequest.setAppKey(iosKey);
            pushRequest.setIOSApnsEnv(env);
            pushRequest.setIOSMutableContent(true);
            pushRequest.setIOSExtParameters(paramJson); //通知的扩展属性(注意 :该参数要以json map的格式传入,否则会解析出错)
            pushRequest.setIOSRemind(false);//消息推送时设备不在线（既与移动推送的服务端的长连接通道不通），则这条推送会做为通知，通过苹果的APNs通道送达一次。注意：离线消息转通知仅适用于生产环境
            pushRequest.setIOSRemindBody(aliPushVo.getBody());
        } else if("ANDROID".equals(aliPushVo.getDeviceType())){
            pushRequest.setAppKey(androidKey);
            pushRequest.setAndroidExtParameters(paramJson);
        } else {
            pushRequest.setAppKey(iosKey);
            pushRequest.setIOSApnsEnv(env);
            pushRequest.setIOSMutableContent(true);
            pushRequest.setIOSExtParameters(paramJson); //通知的扩展属性(注意 :该参数要以json map的格式传入,否则会解析出错)
            pushRequest.setIOSRemind(false);//消息推送时设备不在线（既与移动推送的服务端的长连接通道不通），则这条推送会做为通知，通过苹果的APNs通道送达一次。注意：离线消息转通知仅适用于生产环境
            pushRequest.setIOSRemindBody(aliPushVo.getBody());

            pushRequest.setAppKey(androidKey);
            pushRequest.setAndroidExtParameters(paramJson);

        }

        // 推送控制
        Date pushDate=new Date(System.currentTimeMillis()); // 30秒之间的时间点,也可以设置成你指定固定时间
        String pushTime=ParameterHelper.getISO8601Time(pushDate);
        pushRequest.setPushTime(pushTime); // 延后推送。可选，如果不设置表示立即推送
        String expireTime=ParameterHelper.getISO8601Time(new Date(System.currentTimeMillis() + 12 * 3600 * 1000)); // 12小时后消息失效,不会再发送
        pushRequest.setExpireTime(expireTime);
        if(aliPushVo.getPushType().equals(AppPushTypeEnum.NOTICE.getName())) {
            //通知：离线消息保存
            pushRequest.setStoreOffline(true); // 离线消息是否保存,若保存, 在推送时候，用户即使不在线，下一次上线则会收到
        }else {
            //消息：离线消息不保存
            pushRequest.setStoreOffline(false);
        }

        return this.getClient().getAcsResponse(pushRequest);

    }


    /**
     * 取消定时推送
     * <p>
     * //
     */
    public CancelPushResponse cancelPush(Long AppKey,Long messageId) throws Exception {
        CancelPushRequest request=new CancelPushRequest();
        request.setAppKey(AppKey);
        request.setMessageId(messageId);

        return this.getClient().getAcsResponse(request);

    }

    /**
     * 通过别名查询设备号
     *
     * @param appKey
     * @param alias
     * @return
     * @throws ServerException
     * @throws ClientException
     */
    public List<String> queryDeviceIds(long appKey,String alias) throws ServerException, ClientException {
        QueryDevicesByAliasRequest request=new QueryDevicesByAliasRequest();
        request.setAppKey(appKey);
        request.setAlias(alias);
        request.setActionName("QueryDevicesByAlias");

        QueryDevicesByAliasResponse response=this.getClient().getAcsResponse(request);
        return response.getDeviceIds();
    }

    /**
     * 查询别名 参考文档 ：https://help.aliyun.com/document_detail/48078.html
     */
    public List<String> queryAliases(long appKey,String deviceId) throws Exception {

        QueryAliasesRequest request=new QueryAliasesRequest();
        request.setAppKey(appKey);
        request.setDeviceId(deviceId);

        QueryAliasesResponse response=this.getClient().getAcsResponse(request);
        List<String> aliasNames=new ArrayList<>();
        for (QueryAliasesResponse.AliasInfo aliasInfo : response.getAliasInfos()) {
            aliasNames.add(aliasInfo.getAliasName());
        }
        return aliasNames;
    }

    /**
     * 绑定别名 参考文档 ：https://help.aliyun.com/document_detail/48079.html
     */

    public BindAliasResponse bindAlias(long appKey,String deviceId,String alias) throws Exception {

        BindAliasRequest request=new BindAliasRequest();
        request.setAppKey(appKey);
        request.setDeviceId(deviceId);
        request.setAliasName(alias);
        return this.getClient().getAcsResponse(request);
    }

    /**
     * 解绑别名 https://help.aliyun.com/document_detail/48080.html
     */

    public UnbindAliasResponse unbindAlias(long appKey,String deviceId,String alias) throws Exception {

        UnbindAliasRequest request=new UnbindAliasRequest();
        request.setAppKey(appKey);
        request.setDeviceId(deviceId);
        request.setAliasName(alias);

        return this.getClient().getAcsResponse(request);
    }


}
